package com.easyaop.test.core.demo;

import com.easyaop.test.core.entity.Bean;
import com.easyaop.test.core.intercept.VirtualMethodAdvice;
import com.easyaop.test.core.listener.DebugAgentListener;
import com.easyaop.test.core.pointcut.MethodPointcut;
import com.easyaop.test.core.pointcut.MethodPointcutWrapper;

import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;

import java.io.File;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;

/**
 * @author lipan
 * @since 2025-01-20
 */
public class ByteBuddyTest2 {
    private static final String ROOT_PATH = "D:/project/workspace/aop";

    public static void main(String[] args) throws UnmodifiableClassException {
        Instrumentation install = ByteBuddyAgent.install();
        Bean bean2 = new Bean();

        MethodPointcut pointcut = MethodPointcut.forMethodPointcut(Bean.class, "getName", String.class);

        MethodPointcutWrapper wrapper = MethodPointcutWrapper.wrapper(pointcut);

        new AgentBuilder.Default()
                .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) // 启用重定义策略
                .disableClassFormatChanges()
                .type(pointcut.getClassNameMatcher()) // 指定需要拦截的类
                .transform(getTransformer(wrapper))
                .with(getListener())
                .installOn(install);

        Bean bean = new Bean();
        bean.setId(1L);
        bean.setName("lp");

        final String beanName = bean.getName();
        System.out.println(beanName);
    }

    private static AgentBuilder.Transformer getTransformer(MethodPointcutWrapper wrapper) {
        ElementMatcher<? super MethodDescription> matcher = wrapper.getMethodMatcher();
        return (builder, typeDescription, classLoader, javaModule, protectionDomain) -> {
            builder.method(matcher);
            return builder.visit(Advice.to(VirtualMethodAdvice.class).on(matcher));
        };
    }

    private static AgentBuilder.Listener getListener() {
        return new DebugAgentListener();
    }

    static {
        String path = ROOT_PATH + File.separator + "DUMP_CLASS";
        System.setProperty(DebugAgentListener.DEBUG_LOCATION_PROPERTY, path);
    }
}
